package com.aop.config;

import com.aop.annotation.ExtTransaction;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;

import java.lang.reflect.Method;

/**
 * @author xinwang
 * @date 2020/2/25 16:18
 **/
@Aspect  //自定义事务注解实现
@Component
public class AopExtTransaction {
    @Autowired
    private TransactionUtils transactionUtils;

    @Pointcut("execution(* com.aop.service.*.*.*(..))")
    public void pointcut() {
    }


    @Around("pointcut()")//环绕通知
    private void around(ProceedingJoinPoint point) throws Throwable {

        ExtTransaction extTransaction = getMethodExtTransaction(point);

        TransactionStatus transactionStatus = OpenTransaction(extTransaction);
        //4.调用目标方法
        point.proceed();
        CommitTransaction(transactionStatus);
    }

    /**
     * 获取 目标对象方法是否加有 自定义注解(@ExtTransaction)
     *
     * @param point
     * @return
     * @throws NoSuchMethodException
     */
    private ExtTransaction getMethodExtTransaction(ProceedingJoinPoint point) throws NoSuchMethodException {
        //1.获取代理对象
        //获取代理对象方法
        String methodName = point.getSignature().getName();
        //获取到目标对象
        Class<?> classTarget = point.getTarget().getClass();
        //获取目标对象类型
        Class[] par = ((MethodSignature) point.getSignature()).getParameterTypes();
        //获取目标方法
        Method method = classTarget.getMethod(methodName, par);
        return method.getDeclaredAnnotation(ExtTransaction.class);
    }

    /**
     * 存在自定义注解开启事务 返回事务状态
     *
     * @param extTransaction  当前注解对象
     * @return
     */
    private TransactionStatus OpenTransaction(ExtTransaction extTransaction) {
        //2.获取该方法是否有该注解
        if (extTransaction != null) {
            //3.存在注解开启事务
            return transactionUtils.begin();
        }
        return null;
    }

    /**
     * 判断当前事务是否为null  否则提交事务
     *
     * @param transactionStatus  当前事务状态
     */
    private void CommitTransaction(TransactionStatus transactionStatus) {
        //5.判断该事务是否存在
        if (transactionStatus != null) {
            //6.提交事务
            transactionUtils.commit(transactionStatus);
        }
    }

    @AfterThrowing("pointcut()")
    public  void afterThrowing(){
        transactionUtils.rollback();
    }
}

